﻿#include <iostream>
#include "../src/vkApplication.h"

using namespace std;

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CLIENT_WIDTH 800
#define CLIENT_HEIGHT 600


typedef struct
{
	VkSurfaceCapabilitiesKHR caps;
	vector<VkSurfaceFormatKHR> formats;
	vector<VkPresentModeKHR> presentModes;
} SwapChainSupportDetails;

/*
 * Return 1 (true) if all layer names specified in check_names
 * can be found in given layer properties.
 */
static VkBool32 demo_check_layers(uint32_t check_count, char **check_names, uint32_t layer_count, VkLayerProperties *layers) {
	for (uint32_t i = 0; i < check_count; i++) {
		VkBool32 found = 0;
		for (uint32_t j = 0; j < layer_count; j++) {
			if (!strcmp(check_names[i], layers[j].layerName)) {
				found = 1;
				break;
			}
		}
		if (!found) {
			fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
			return 0;
		}
	}
	return 1;
}

bool VkSimpleApplication::InitApp()
{
	cout << "---------- Begin InitApp ----------" << endl;
	glfwInit();

	// 查询有效校验层
	uint32_t layerCnt;
	VkResult result = vkEnumerateInstanceLayerProperties(&layerCnt, NULL);
	if (result != VK_SUCCESS)
	{
		cout << "vkEnumerateInstanceLayerProperties layerCount: " << result << endl;
		return false;
	}

	if (layerCnt <= 0) {
		cout << "vkEnumerateInstanceLayerProperties layerCount: zero" << endl;
		return false;
	}


	char *instance_validation_layers[] = { "VK_LAYER_KHRONOS_validation" };

	vector<VkLayerProperties> props(layerCnt);
		result = vkEnumerateInstanceLayerProperties(&layerCnt, props.data());
		if (result != VK_SUCCESS)
		{
			cout << "vkEnumerateInstanceLayerProperties: " << result << endl;
			return false;
		}

		//cout << endl << "-------- Begin InstanceLayerProps ---------" << endl;
		for (auto iter = props.begin(); iter != props.end(); ++iter)
		{
			cout << "【LayerName】 " << iter->layerName << " 【descript】 " << iter->description << 
				" 【Version】 " << iter->specVersion << "【Impl Version】" << iter->implementationVersion << endl;
		}
		//cout << endl << "-------- End InstanceLayerProps ---------" << endl;

		VkBool32 validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers,
			layerCnt, props.data());

		if (!validation_found)
		{
			cout << "not found: VK_LAYER_KHRONOS_validation" << endl;
			return false;
		}

	PrintExtends();

	// 创建Instance
	VkApplicationInfo appInfo = {};
	appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
	appInfo.pApplicationName = "vkSimpleApplication";
	appInfo.applicationVersion = VK_MAKE_VERSION(1, 2, 0);
	appInfo.pEngineName = "Softward CPU RenderPipline";
	appInfo.engineVersion = VK_MAKE_VERSION(1, 2, 0);
	appInfo.apiVersion = VK_API_VERSION_1_2;

	// GLFW扩展特性
	uint32_t glfwExtCnt = 0;
	auto glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtCnt);
	std::vector<const char*> ext(glfwExtCnt);
	for (int i = 0; i < glfwExtCnt; ++i)
	{
		ext[i] = glfwExtensions[i];
	}

	// 交换链
	//ext.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

	VkInstanceCreateInfo createInfo = {};
	createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
	createInfo.pApplicationInfo = &appInfo;
	// 全局校验层
	createInfo.enabledLayerCount = 0;
	createInfo.enabledExtensionCount = ext.size();
	createInfo.ppEnabledExtensionNames = ext.data();
	//createInfo.enabledLayerCount = layerCnt;
	//createInfo.ppEnabledLayerNames = (const char *const *)instance_validation_layers;
	result =  vkCreateInstance(&createInfo, m_Allocator, &m_Instance);
	if (result != VK_SUCCESS)
	{
		cout << "CreateInstance Error: " << result << endl;
		return false;
	}

	if (!InitPhysicDevice())
		return false;


	if (!InitWindow())
		return false;

	if (!InitSwapChain())
		return false;
	cout << "---------- End InitApp ----------" << endl;

	return true;
}

static uint32_t PhysicalDeviceSuitability(VkPhysicalDevice& device)
{
	
	// 必须支持SwapChain
	uint32_t extCnt = 0;
	
	if (vkEnumerateDeviceExtensionProperties(device, NULL, &extCnt, NULL) != VK_SUCCESS)
		return -1;

	std::vector<VkExtensionProperties> extProps(extCnt);
	if (vkEnumerateDeviceExtensionProperties(device, NULL, &extCnt, extProps.data()) != VK_SUCCESS)
		return -1;

	bool isFoundExt = false;
	for (auto iter = extProps.begin(); iter != extProps.end(); ++iter)
	{
		if (strcmp(iter->extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
		{
			isFoundExt = true;
			break;
		}
	}

	if (!isFoundExt)
		return -1;

	uint32_t ret = 0;
	VkPhysicalDeviceProperties props = {};
	vkGetPhysicalDeviceProperties(device, &props);
	if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
		ret += 1000000;
	ret += props.limits.maxImageDimension2D;
	

	VkPhysicalDeviceFeatures features = {};
	vkGetPhysicalDeviceFeatures(device, &features);

	// 几何SHADER
	if (features.geometryShader)
		ret += 10000;

	// 细分SHADER
	if (features.tessellationShader)
		ret += 10000;

	return ret;
}

bool VkSimpleApplication::InitSwapChain()
{
	if (m_PhsicalDevice && m_FrontSurface)
	{
		SwapChainSupportDetails details = {};
		if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_PhsicalDevice, m_FrontSurface, &details.caps) == VK_SUCCESS)
		{
			cout << "maxImageCount: " << details.caps.maxImageCount << endl;
		}

		uint32_t formatCnt = 0;
		vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhsicalDevice, m_FrontSurface, &formatCnt, NULL);
		if (formatCnt <= 0)
			return false;
		bool isFound = false;
		details.formats.resize(formatCnt);
		vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhsicalDevice, m_FrontSurface, &formatCnt, details.formats.data());
		for (auto iter = details.formats.begin(); iter != details.formats.end(); ++iter)
		{
			cout << "【ColorSpace】" << iter->colorSpace << "【Format】" << iter->format << endl;
			if (iter->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR && iter->format == VK_FORMAT_B8G8R8A8_UNORM)
			{
				isFound = true;
			}
		}
		if (!isFound)
			return false;

		uint32_t presentCnt = 0;
		vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhsicalDevice, m_FrontSurface, &presentCnt, NULL);
		if (presentCnt <= 0)
			return false;
		details.presentModes.resize(presentCnt);
		
		VkPresentModeKHR mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
		vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhsicalDevice, m_FrontSurface, &presentCnt, details.presentModes.data());
		for (auto iter = details.presentModes.begin(); iter != details.presentModes.end(); ++iter)
		{
			cout << "【Present Mode】" << *iter << endl;

			if (*iter == VK_PRESENT_MODE_MAILBOX_KHR)
				mode = VK_PRESENT_MODE_MAILBOX_KHR;
		}

		uint32_t w = CLIENT_WIDTH;
		uint32_t h = CLIENT_HEIGHT;
		if (w < details.caps.minImageExtent.width)
			w = details.caps.minImageExtent.width;
		if (w > details.caps.maxImageExtent.width)
			w = details.caps.maxImageExtent.width;
		if (h < details.caps.minImageExtent.height)
			h = details.caps.minImageExtent.height;
		if (h > details.caps.maxImageExtent.height)
			h = details.caps.maxImageExtent.height;

		VkSwapchainCreateInfoKHR createInfo = {};
		createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
		createInfo.surface = m_FrontSurface;
		createInfo.minImageCount = details.caps.minImageCount + 1;
		createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
		createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
		createInfo.imageExtent.width = w;
		createInfo.imageExtent.height = h;
		createInfo.imageArrayLayers = 1;
		createInfo.presentMode = mode;
		createInfo.clipped = VK_TRUE;
		createInfo.oldSwapchain = VK_NULL_HANDLE;
		// 不和原來窗體顔色混合
		createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;

		//如果读者需要对图像进行后期处理之类的操作，可以使用
		//VK_IMAGE_USAGE_TRANSFER_DST_BIT 作为imageUsage 成员变
		//	量的值，让交换链图像可以作为传输的目的图像。
		createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
		
		if (vkCreateSwapchainKHR(m_Device, &createInfo, m_Allocator, &m_swapChain) != VK_SUCCESS)
			return false;

		uint32_t imageViewCnt = 0;
		vkGetSwapchainImagesKHR(m_Device, m_swapChain, &imageViewCnt, NULL);
		if (imageViewCnt <= 0)
			return false;
		m_ImageViews.resize(imageViewCnt);
		vkGetSwapchainImagesKHR(m_Device, m_swapChain, &imageViewCnt, m_ImageViews.data());

		return true;
	}	
	else
		return false;
}

bool VkSimpleApplication::InitPhysicDevice()
{
	if (!m_Instance)
		return false;
	VkPhysicalDevice device = NULL;
	uint32_t deviceCnt = 0;
	int selQueue = -1;
	VkResult result = vkEnumeratePhysicalDevices(m_Instance, &deviceCnt, NULL);
	if (result != VK_SUCCESS)
	{
		cout << "InitPhysicDevice: " << result << endl;
		return false;
	}

	vector<VkPhysicalDevice> devices(deviceCnt);
	result = vkEnumeratePhysicalDevices(m_Instance, &deviceCnt, devices.data());
	if (result != VK_SUCCESS)
	{
		cout << "InitPhysicDevice: " << result << endl;
		return false;
	}

	// 设置设备需求

	uint32_t deviceAbility = 0;
	for (auto iter = devices.begin(); iter != devices.end(); ++iter)
	{
		VkPhysicalDeviceProperties props = {};
		vkGetPhysicalDeviceProperties(*iter, &props);
		cout << "【Device ID】" << props.deviceID << "【Device Name】" << props.deviceName
			<< "【Device Type】" << props.deviceType << "【Version】" << props.driverVersion
			<< "【VendID】" << props.vendorID << endl;

		// 检测设备是否支持队列族

		uint32_t queuePropCnt = 0;
		vkGetPhysicalDeviceQueueFamilyProperties(*iter, &queuePropCnt, NULL);
		if (queuePropCnt <= 0)
			continue;

		vector<VkQueueFamilyProperties> familyProps(queuePropCnt);
		vkGetPhysicalDeviceQueueFamilyProperties(*iter, &queuePropCnt, familyProps.data());

		bool isFound = false;
		int idx = -1;
		for (auto fIter = familyProps.begin(); fIter != familyProps.end(); ++fIter)
		{
			if ((fIter->queueCount > 0) && (fIter->queueFlags & VK_QUEUE_GRAPHICS_BIT))
			{
				++idx;
				cout << "【Device Queue Faimily 】QueueCount: " << fIter->queueCount << endl;
				isFound = true;
				break;
			}
			
		}

		if (!isFound || idx < 0)
			continue;

		//VkPhysicalDeviceFeatures features = {};
		//vkGetPhysicalDeviceFeatures(*iter, &features);
		uint32_t ability = PhysicalDeviceSuitability(*iter);
		if (ability > deviceAbility)
		{
			deviceAbility = ability;
			device = *iter;
			selQueue = idx;
		}

	}

	if (!device || selQueue < 0)
		return false;

	m_PhsicalDevice = device;

	cout << "--------- selected PhysicalDevice -------------" << endl;
	VkPhysicalDeviceProperties props = {};
	vkGetPhysicalDeviceProperties(m_PhsicalDevice, &props);
	cout << "【Device ID】" << props.deviceID << "【Device Name】" << props.deviceName
		<< "【Device Type】" << props.deviceType << "【Version】" << props.driverVersion
		<< "【VendID】" << props.vendorID << endl;



	//------- 创建逻辑设备

		// 逻辑设备和物理设备之间的队列
	VkDeviceQueueCreateInfo deviceQueueInfo = {};
	deviceQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	deviceQueueInfo.queueFamilyIndex = selQueue;
	deviceQueueInfo.queueCount = 1;
	// 队列优先级
	float queuePriority = 1.0f;
	deviceQueueInfo.pQueuePriorities = &queuePriority;

	// 创建逻辑设备
	VkDeviceCreateInfo deviceInfo = {};
	deviceInfo.pQueueCreateInfos = &deviceQueueInfo;
	deviceInfo.queueCreateInfoCount = 1;

	VkPhysicalDeviceFeatures features = {};
	vkGetPhysicalDeviceFeatures(m_PhsicalDevice, &features);
	// 逻辑设备需要开启的设备特性
	deviceInfo.pEnabledFeatures = &features;
	deviceInfo.enabledLayerCount = 0;
	// 扩展
	std::vector<const char*> deviceExts = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
	deviceInfo.enabledExtensionCount = deviceExts.size();
	deviceInfo.ppEnabledExtensionNames = deviceExts.data();

	result = vkCreateDevice(m_PhsicalDevice, &deviceInfo, m_Allocator, &m_Device);
	if (result != VK_SUCCESS)
	{
		cout << "vkCreateDevice Failed: " << result << endl;
		return false;
	}
	// 获得队列
	vkGetDeviceQueue(m_Device, selQueue, 0, &m_Queue);

	return true;
}

bool VkSimpleApplication::Run()
{
	if (m_Window && !glfwWindowShouldClose(m_Window))
	{
		glfwPollEvents();
		return true;
	}
	return false;
}

void VkSimpleApplication::Quit()
{
	cout << "--------------------- Start Quit --------------------" << endl;
	m_ImageViews.swap(vector<VkImageView>());
	if (m_swapChain != 0)
	{
		cout << ">>DestroySwapChain" << endl;
		vkDestroySwapchainKHR(m_Device, m_swapChain, m_Allocator);
		m_swapChain = 0;
	}
	if (m_FrontSurface != 0)
	{
		cout << ">>DestroySurface" << endl;
		vkDestroySurfaceKHR(m_Instance, m_FrontSurface, m_Allocator);
		m_FrontSurface = 0;
	}

	if (m_Queue)
	{
		m_Queue = NULL;
	}
	if (m_Device)
	{
		cout << ">>DestroyVulkanDevice" << endl;
		vkDestroyDevice(m_Device, m_Allocator);
		m_Device = NULL;
	}
	if (m_PhsicalDevice)
	{
		m_PhsicalDevice = NULL;
	}
	if (m_Instance) {
		cout << ">>DestroyVulkanInstance" << endl;
		vkDestroyInstance(m_Instance, m_Allocator);
		m_Instance = NULL;
	}

	if (m_Window)
	{
		cout << ">>DestroyWindow" << endl;
		glfwDestroyWindow(m_Window);
		m_Window = NULL;
	}

	cout << ">>Terminate" << endl;
	glfwTerminate();

	cout << "--------------------- End Quit --------------------" << endl;
}

bool VkSimpleApplication::InitWindow()
{
	cout << "---------- Begin InitWindow ----------" << endl;

	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
	glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
	m_Window = glfwCreateWindow(CLIENT_WIDTH, CLIENT_HEIGHT, "CPU RenderPipline", NULL, NULL);

	VkResult result = glfwCreateWindowSurface(m_Instance, m_Window, m_Allocator, &m_FrontSurface);
	if (result != VK_SUCCESS)
	{
		cout << "glfwCreateWindowSurface Failed: " << result << endl;
		return false;
	}

	cout << "---------- End InitWindow ----------" << endl;
	// 初始化窗体
	return true;
}

VkSimpleApplication::VkSimpleApplication(): m_Instance(NULL), m_Allocator(NULL), m_PhsicalDevice(NULL), m_Device(NULL), m_Queue(NULL)
{
	m_FrontSurface = 0;
	m_Window = NULL;
}

void VkSimpleApplication::PrintExtends()
{
	uint32_t extensionCount = 0;
	VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL);
	if (result != VK_SUCCESS)
	{
		cout << "vkEnumerateInstanceExtensionProperties: " << result << endl;
		return;
	}

	if (extensionCount <= 0)
		return;

	vector<VkExtensionProperties> props(extensionCount);
	result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, props.data());
	if (result != VK_SUCCESS)
	{
		cout << "vkEnumerateInstanceExtensionProperties info: " << result << endl;
		return;
	}
	for (auto iter = props.begin(); iter != props.end(); ++iter)
	{
		cout << "【extend Name】 " << iter->extensionName << " 【version】 " << iter->specVersion << endl;
	}
}